//%module(package="Scopes") "Scopes::Array"
%{
   #include "array.h"

/*   arrayI8* new_arrayI8(SV* sv){
      return new arrayI8();
   }*/
template <class T> array<T>* arrayFromSV(SV* sv){
   if (SvIOK(sv) || SvNOK(sv)){
      long h=(long) SvIV(sv);
      if (h<0) {
         std::cout << "illegal argument to array constructor (perl wrapper); empty array created." << std::endl;
         return new array<T>();
      }
      return new array<T>((size_t) h);
   } else if (SvROK(sv)){
      SV* y=SvRV(sv);
      if (SvTYPE(y)==SVt_PVAV){
         array<T>* newar=new array<T>();
         AV* ar=(AV*) y;
         size_t len = av_len(ar)+1;
         size_t i;
         newar->resize(len);
         for (i=0;i<len;i++) {
            SV** x = av_fetch(ar, (I32) i, 0);
            if (SvIOK(*x)) (*newar)[i] = (T) SvIV(*x);
            if (SvNOK(*x) || SvPOK(*x)) (*newar)[i] = (T) SvNV(*x); //allow strings like "1" as array elements
         }
         return newar;
      }
      std::cout << "illegal argument to array constructor (perl wrapper); empty array created." << std::endl;
      return new array<T>();
   } else {
      std::cout << "illegal argument to array constructor (perl wrapper); empty array created." << std::endl;
      return new array<T>();
   }
}
%}
%include "std_string.i"
%newobject which;
%newobject whichEq;
%newobject whichLt;
%newobject whichLe;
%newobject whichGt;
%newobject whichGe;
%newobject copy;
%newobject selectGet;

/* limited version of std:vector to build wrapper */
/*%import minivector.i*/
/*template <class T> class std::vector{
};*/
typedef size_t size_type;
%include "array.h"
/*template <class T> class array{
   public:
      array<T>();
      std::string printToString();
      void print();
      template <class T2> void add(array<T2>& ar2);
};*/

%extend array{
   array<T>(SV* sv){
      return arrayFromSV<T>(sv);
   }
   SV* toa(){
      AV* ret;
      size_t i;
      ret=newAV();
      for (i=0;i<$self->size();i++){
         if (TisReal<T>()){ //defined in array.h
            av_push(ret,newSVnv((*($self))[i])); //we actually need a specific implementation for real types like double or float
         } else {
            av_push(ret,newSViv((long) (*($self))[i])); 
         }
      }
      return (sv_2mortal(newRV_noinc((SV*) ret)));
   }
   size_t size(){
      return $self->size();
   }
   void resize(size_t sz){
      $self->resize(sz);
   }
   void assign(size_t n,const T& u){
      $self->assign(n,u);
   }
}

// resolve template methods before template class
%template(put) array::put<unsigned char>;
%template(add) array::add<unsigned char>;
%template(sub) array::sub<unsigned char>;
%template(isEq) array::isEq<unsigned char>;
%template(isSubsetOf) array::isSubsetOf<unsigned char>;
%template(isSetEq) array::isSetEq<unsigned char>;
%template(AND) array::AND<unsigned char>;
%template(OR) array::OR<unsigned char>;
%template(XOR) array::XOR<unsigned char>;
%template(subSet) array::subSet<unsigned char>;
%template(ANDnz) array::ANDnz<unsigned char>;
%template(ORnz) array::ORnz<unsigned char>;
%template(XORnz) array::XORnz<unsigned char>;
%template(subSetnz) array::subSetnz<unsigned char>;

%template(put) array::put<size_t>;
%template(add) array::add<size_t>;
%template(sub) array::sub<size_t>;
%template(isEq) array::isEq<size_t>;
%template(isSubsetOf) array::isSubsetOf<size_t>;
%template(isSetEq) array::isSetEq<size_t>;
%template(AND) array::AND<size_t>;
%template(OR) array::OR<size_t>;
%template(XOR) array::XOR<size_t>;
%template(subSet) array::subSet<size_t>;
%template(ANDnz) array::ANDnz<size_t>;
%template(ORnz) array::ORnz<size_t>;
%template(XORnz) array::XORnz<size_t>;
%template(subSetnz) array::subSetnz<size_t>;

%template(put) array::put<long>;
%template(add) array::add<long>;
%template(sub) array::sub<long>;
%template(isEq) array::isEq<long>;
%template(isSubsetOf) array::isSubsetOf<long>;
%template(isSetEq) array::isSetEq<long>;
%template(AND) array::AND<long>;
%template(OR) array::OR<long>;
%template(XOR) array::XOR<long>;
%template(subSet) array::subSet<long>;
%template(ANDnz) array::ANDnz<long>;
%template(ORnz) array::ORnz<long>;
%template(XORnz) array::XORnz<long>;
%template(subSetnz) array::subSetnz<long>;

%template(put) array::put<float>;
%template(add) array::add<float>;
%template(sub) array::sub<float>;
%template(isEq) array::isEq<float>;
%template(isSubsetOf) array::isSubsetOf<float>;
%template(isSetEq) array::isSetEq<float>;
%template(AND) array::AND<float>;
%template(OR) array::OR<float>;
%template(XOR) array::XOR<float>;
%template(subSet) array::subSet<float>;
%template(ANDnz) array::ANDnz<float>;
%template(ORnz) array::ORnz<float>;
%template(XORnz) array::XORnz<float>;
%template(subSetnz) array::subSetnz<float>;

%template(ArrayU8) array<unsigned char>;
%template(ArrayS) array<size_t>;
%template(ArrayI32) array<long>;
%template(ArrayF) array<float>;
%perlcode %{
push @Scopes::ArrayU8::ISA,'Scopes::Array';
push @Scopes::ArrayS::ISA,'Scopes::Array';
push @Scopes::ArrayI32::ISA,'Scopes::Array';
push @Scopes::ArrayF::ISA,'Scopes::Array';
package Scopes::Array;
#   use overload '""' => sub{
#  my $self=shift;
#   $|=1;
#   print caller(1)[3];
#   sleep(1);
#   return $self->printToString;
#};
%}
